package com.CmJava.handler;

import com.CmJava.entity.IdelUser;
import com.CmJava.entity.PrivateUser;
import com.CmJava.service.MessageService;
import com.alibaba.dubbo.config.annotation.Reference;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.timeout.IdleStateEvent;

import java.text.SimpleDateFormat;
import java.util.*;


//这里 TextWebSocketFrame 类型，表示一个文本帧(frame)
public class MyHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {


    private static HashMap<IdelUser, Channel> idelChannels;

    private static HashMap<PrivateUser, List<Channel>> privateUserChannel = new HashMap<>();

    private static HashMap<String, String[]> imgPack = new HashMap<>();

    private static SimpleDateFormat thisMoment;

    private MessageService messageService;

    public MyHandler(HashMap<IdelUser, Channel> channels, SimpleDateFormat thisMoment,MessageService messageService) {
        this.idelChannels = channels;
        this.thisMoment = thisMoment;
        this.messageService = messageService;
    }


    // 第一个被调用的，连接建立调用
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {


    }

    // 连接断开则调用，通知channel组内所有人
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {


    }

    // 通道激活则调用，给服务器看
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        System.out.println(ctx.channel().remoteAddress() + "上线");
    }

    // 通道关闭则调用，给服务器看
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Channel channel = ctx.channel();
        removeChannel(idelChannels, privateUserChannel, channel);
        ctx.close();
        System.out.println(ctx.channel().remoteAddress() + "下线");
    }


    // 读取客户端发来的消息，并发送
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        Channel channel = ctx.channel();

        //刚上线，向所有组内用户发送通知
        if (msg.text().contains("昵称是：")) {
            // 昵称为空会抛异常
            String name = msg.text().split("：")[1];
            // 加入channel组
            IdelUser idelUser = new IdelUser(name, channel.remoteAddress().toString());
            idelChannels.put(idelUser, channel);
            for (Channel channel1 : idelChannels.values()) {
                channel1.writeAndFlush(new TextWebSocketFrame("@@加入聊天@@：" + name + "@@在线用户数@@：" + idelChannels.size()));
            }
        } else if (msg.text().contains("@@当前闲聊在线@@")) {
            // 获取闲聊在线列表
            Set<IdelUser> idelUsers = idelChannels.keySet();
            String idelUsersList = "";
            for (IdelUser idelUser : idelUsers) {
                idelUsersList += idelUser.getName() + ",";
            }
            idelUsersList = idelUsersList.substring(0, idelUsersList.length() - 1);
            channel.writeAndFlush(new TextWebSocketFrame("@@当前闲聊在线@@：" + idelUsersList));
        } else if (msg.text().contains("@@好友上线@@：")) {

            String username = msg.text().split("：")[1];
            String friendList = msg.text().split("：")[3];
            ArrayList<Channel> channels = new ArrayList<>();
            String friendList1 = "";
            if (!friendList.equals("--")) {
                String[] friendList0 = friendList.split(",");
                Set<PrivateUser> privateUsers = privateUserChannel.keySet();
                channels.add(channel);
                for (String friend : friendList0) {
                    for (PrivateUser privateUser : privateUsers) {
                        if (friend.equals(privateUser.getName())) {
                            friendList1 += friend + ",";
                            //通知好友上线
                            Channel channel1 = privateUserChannel.get(privateUser).get(0);
                            channel1.writeAndFlush(new TextWebSocketFrame("@@好友上线@@：" + username));
                            privateUserChannel.get(privateUser).add(channel);
                            channels.add(channel1);
                        }
                    }
                }
            }

            privateUserChannel.put(new PrivateUser(username, channel.remoteAddress().toString()), channels);
            if (friendList1.equals("")) {
                channel.writeAndFlush(new TextWebSocketFrame("@@在线列表@@：--"));
            } else {
                channel.writeAndFlush(new TextWebSocketFrame("@@在线列表@@：" + friendList1.substring(0, friendList1.length() - 1)));
            }
        } else if (msg.text().contains("@@私聊@@：")) {
            // 发送私聊
            // 发送对象
            String userName = msg.text().split("：")[1];

            String message = msg.text().split("：")[2];

            //发送者
            String userName0 = "";
            for (PrivateUser privateUser : privateUserChannel.keySet()) {
                if (privateUserChannel.get(privateUser).get(0) == channel) {
                    userName0 = privateUser.getName();
                    break;
                }
            }
            int num = 0;
            for (PrivateUser privateUser : privateUserChannel.keySet()) {
                if (privateUser.getName().equals(userName)) {
                    privateUserChannel.get(privateUser).get(0).writeAndFlush(new TextWebSocketFrame("@@私聊来自@@：" + userName0 + "：" + message + "：" + thisMoment.format(new Date())));
                    num++;
                    break;
                }
            }
            //接收者不在线
            if (num == 0) {


            }
            channel.writeAndFlush(new TextWebSocketFrame("@@私聊来自我@@：" + userName + "：" + message + "：" + thisMoment.format(new Date())));


            //保存聊天记录
            messageService.saveMessage(userName0,userName,message,thisMoment.format(new Date()),0);
            messageService.saveMessage(userName,userName0,message,thisMoment.format(new Date()),1);

        } else if (msg.text().contains("@@私聊图片@@：")) {

            //发送者
            String userName = getUser0(privateUserChannel, channel).getName();

            //接收者
            String reciver = msg.text().split("：")[1];
            String imgPackage = msg.text().split("：")[2];
            String packaegNum  = msg.text().split("：")[3];
            String totalNum  = msg.text().split("：")[4];
            String key = userName + "to" + reciver;

            if (imgPack.containsKey(key)) {
                imgPack.get(key)[Integer.parseInt(packaegNum)] = imgPackage;
            }else {
                String[] strings = new String[Integer.parseInt(totalNum)];
                strings[Integer.parseInt(packaegNum)] = imgPackage;
                imgPack.put(key, strings);
            }

            for (int i = 0; i < imgPack.get(key).length; i++) {
                System.out.println(imgPack.get(key)[i]);
            }

            //数据接收满了就发送
            if (Integer.parseInt(packaegNum)==Integer.parseInt(totalNum)-1) {

                boolean flag = true;
                for (String s : imgPack.get(key)) {
                    if (s.equals("") || s == null) {
                        flag = false;
                    }
                }

                if (flag) {
                    int num = 0;
                    Channel channel1 = null;
                    //寻找接收者channel
                    for (PrivateUser privateUser : privateUserChannel.keySet()) {
                        if (privateUser.getName().equals(reciver)) {
                            channel1 = privateUserChannel.get(privateUser).get(0);
                            num++;
                            break;
                        }
                    }
                    //接收者不在线
                    if (num == 0) {





                    }
                    //发送图片分包
                    String imgData = "";
                    for (int i = 0; i < imgPack.get(key).length; i++) {
                        if (channel1!=null) {
                            channel1.writeAndFlush(new TextWebSocketFrame("@@私聊图片来自@@：" + userName + "：" + imgPack.get(key)[i] + "：" + thisMoment.format(new Date()) + "：" + i + "：" + totalNum));
                        }
                        channel.writeAndFlush(new TextWebSocketFrame("@@私聊图片来自我@@：" + reciver + "：" + imgPack.get(key)[i] + "：" + thisMoment.format(new Date()) + "：" + i + "：" + totalNum));
                        imgData += imgPack.get(key)[i];
                    }

                    imgPack.remove(key);
                messageService.saveMessage(reciver,userName,imgData,thisMoment.format(new Date()),0);
                messageService.saveMessage(userName,reciver,imgData,thisMoment.format(new Date()),1);
                }
            }

        } else if (msg.text().contains("@@私聊文件@@")) {

            String message = msg.text().substring(9);
            String sendName = message.split("：")[0].split("_to_")[0];
            String reciverName = message.split("：")[0].split("_to_")[1];
            String fileName = message.split("：")[1].substring(3);
            String fileSize = message.split("：")[2].substring(10);
            String fileClass = message.split("：")[3].substring(4);


            int num = 0;
            for (PrivateUser privateUser : privateUserChannel.keySet()) {
                if (privateUser.getName().equals(reciverName)) {
                    privateUserChannel.get(privateUser).get(0).writeAndFlush(new TextWebSocketFrame("@@私聊文件来自@@：" + sendName + "：" + message + "：" + thisMoment.format(new Date())));
                    num++;
                    break;
                }
            }
            //接收者不在线
            if (num == 0) {


            }
            channel.writeAndFlush(new TextWebSocketFrame("@@私聊文件来自我@@：" + reciverName + "：" + message + "：" + thisMoment.format(new Date())));

            String saveMessage="qaz私聊wsx文件edc"+"||"+message.split("：")[0]+"||"+fileName+"||"+fileSize+"||"+fileClass;

            //保存聊天记录
            messageService.saveMessage(sendName,reciverName,saveMessage,thisMoment.format(new Date()),0);
            messageService.saveMessage(reciverName,sendName,saveMessage,thisMoment.format(new Date()),1);


        } else {
            // 发送闲聊
            String name = getUser(idelChannels, channel).getName();

            for (Channel channel1 : idelChannels.values()) {
                if (channel1 != channel) {
                    channel1.writeAndFlush(new TextWebSocketFrame("@@" + name + "@@" + "：" + msg.text() + "theTime" + thisMoment.format(new Date())));
                } else {
                    channel1.writeAndFlush(new TextWebSocketFrame("@@我@@：" + msg.text() + "theTime" + thisMoment.format(new Date())));
                }
            }
        }
        System.out.println("当前用户数是" + idelChannels.size());
    }


    //出现异常关闭通道
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.out.println("出现异常关闭通道");
        cause.printStackTrace();
        Channel channel = ctx.channel();
        removeChannel(idelChannels, privateUserChannel, channel);
        ctx.close();
    }


    // 长时间没读写，会被关闭
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        Channel channel = ctx.channel();
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
            switch (idleStateEvent.state()) {
                case READER_IDLE:
                    removeChannel(idelChannels, privateUserChannel, channel);
                    channel.writeAndFlush(new TextWebSocketFrame("@@长时间未操作@@"));
                    ctx.close();
                    break;
                case WRITER_IDLE:
                    removeChannel(idelChannels, privateUserChannel, channel);
                    channel.writeAndFlush(new TextWebSocketFrame("@@长时间未操作@@"));
                    ctx.close();
                    break;
                case ALL_IDLE:
                    removeChannel(idelChannels, privateUserChannel, channel);
                    channel.writeAndFlush(new TextWebSocketFrame("@@长时间未操作@@"));
                    ctx.close();
                    break;
            }
        }
    }

    // 获取channel对应的user
    private IdelUser getUser(HashMap<IdelUser, Channel> idelChannels, Channel channel) {
        for (IdelUser idelUser : idelChannels.keySet()) {
            if (idelChannels.get(idelUser) == channel) {
                return idelUser;
            }
        }
        return null;
    }

    private PrivateUser getUser0(HashMap<PrivateUser, List<Channel>> privateUserChannel, Channel channel) {
        for (PrivateUser privateUser : privateUserChannel.keySet()) {
            if (privateUserChannel.get(privateUser).get(0) == channel) {
                return privateUser;
            }
        }
        return null;
    }

    // 关闭通道
    private void removeChannel(HashMap<IdelUser, Channel> idelChannels, HashMap<PrivateUser, List<Channel>> privateUserChannel, Channel channel) {
        boolean inIdle = false;
        //判断是在哪个通道组的通道
        if (!(getUser(idelChannels, channel) == null && getUser0(privateUserChannel, channel) == null)) {
            for (Channel channel1 : idelChannels.values()) {
                if (channel1 == channel) {
                    inIdle = true;
                    break;
                }
            }
            if (inIdle) {
                String name = getUser(idelChannels, channel).getName();
                for (Channel channel1 : idelChannels.values()) {

                    if (channel1 != channel) {
                        channel1.writeAndFlush(new TextWebSocketFrame("@@离开聊天@@：" + name + "@@在线用户数@@：" + (idelChannels.size() - 1)));
                    }
                }
                idelChannels.remove(getUser(idelChannels, channel));
            } else {

                // 在私聊组
                String name = getUser0(privateUserChannel, channel).getName();
                for (Channel channel1 : privateUserChannel.get(getUser0(privateUserChannel, channel))) {
                    channel1.writeAndFlush(new TextWebSocketFrame("@@好友下线@@：" + name));
                }
                privateUserChannel.remove(getUser0(privateUserChannel, channel));
            }
        }
    }
}
